﻿using System;
using System.IO;
using System.Linq;
using System.Net;
using System.Web;
using System.Xml.Linq;

namespace Core
{
    public class TranslatorService
    {
        private readonly AdmAccessToken _accessToken;

        public TranslatorService(
            string clientId,
            string clientSecret)
        {
            var admAuthenticaton = new AdmAuthentication(clientId, clientSecret);
            _accessToken = admAuthenticaton.GetAccessToken();
        }

        /// <summary>
        /// Translate resources and save transaltions
        /// </summary>
        /// <param name="sampleFile">The sample file from where original text and language has to be referred</param>
        /// <param name="sourceFolder">The folder containning original, non-translated resource files</param>
        /// <param name="targetFolder">The folder where translated resource files will be stored</param>
        /// <returns>Result indicating if translation is successful and related error message, if any</returns>
        public TranslateResult Translate(string sampleFile, string sourceFolder, string targetFolder)
        {
            try
            {
                var rootNode = FileService.GetRootNode(sampleFile);
                var sourceLocale = rootNode.Elements()
                    .Where(e => e.Name == "data")
                    .Single(e => e.Attribute("name").Value == "ResourceLanguage")
                    .Elements("value")
                    .Single()
                    .Value;

                var files = FileService.GetFileNames(sourceFolder);

                foreach (var file in files)
                {
                    //If the file has already been translated, skip the file
                    if (File.Exists(targetFolder + "\\" + Path.GetFileName(file)))
                    {
                        continue;
                    }

                    var language = FileService.GetLocaleDetails(file);

                    //If the file to be translated is the original one, just copy it directly to target as no translation required
                    if (sourceLocale == language.Locale)
                    {
                        File.Copy(file, targetFolder + "\\" + Path.GetFileName(file));

                        continue;
                    }

                    var root = rootNode;
                    var document = new XDocument();

                    foreach (var element in root.Elements("data"))
                    {
                        var name = element.Attribute("name").Value.Trim();
                        var valueElement = element.Elements("value").Single();

                        if (name == "ResourceLanguage")
                        {
                            valueElement.Value = language.Locale;
                            continue;
                        }

                        if (name == "ResourceFlowDirection")
                        {
                            valueElement.Value = language.Direction;
                            continue;
                        }

                        var translateResult = TranslateText(valueElement.Value, sourceLocale, language.Locale);

                        if (!translateResult.Success)
                        {
                            return translateResult;
                        }

                        valueElement.Value = translateResult.Text;
                    }

                    document.Add(root);
                    document.Save(targetFolder + "//" + Path.GetFileName(file));
                }

                return new TranslateResult { Success = true };
            }
            catch (Exception ex)
            {
                return new TranslateResult {Message = ex.Message, Success = false};
            }
        }

        /// <summary>
        /// Translate particular text value
        /// </summary>
        /// <param name="sourceText">Text to translate</param>
        /// <param name="sourceLocale">Source language/culture from which text has to be transalated</param>
        /// <param name="targetLocale">Language/culture to which text has to be translated</param>
        /// <returns>Result indicating if translation is successful and related error message, if any</returns>
        private TranslateResult TranslateText(string sourceText, string sourceLocale, string targetLocale)
        {
            try
            {
                var uri = "http://api.microsofttranslator.com/v2/Http.svc/Translate?text="
                + HttpUtility.UrlEncode(sourceText)
                + "&from=" + sourceLocale
                + "&to=" + targetLocale;

                var authToken = "Bearer" + " " + _accessToken.access_token;

                var httpWebRequest = (HttpWebRequest)WebRequest.Create(uri);

                httpWebRequest.Headers.Add("Authorization", authToken);

                var response = httpWebRequest.GetResponse();

                using (var stream = response.GetResponseStream())
                {
                    var dcs = new System.Runtime.Serialization.DataContractSerializer(Type.GetType("System.String"));
                    var translation = (string)dcs.ReadObject(stream);

                    return new TranslateResult { Success = true, Text = translation };
                }
            }
            catch (Exception ex)
            {
                return new TranslateResult { Success = false, Message = ex.Message };
            }
        }
    }
}
